/*
 * DIM-SUM操作系统 - 处理器相关
 *
 * Copyright (C) 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Dong Peng <w-pengdong@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#ifndef __ASM_PROCESSOR_H
#define __ASM_PROCESSOR_H

#ifndef __ASSEMBLY__

#include <dim-sum/mm_types.h>
#include <asm/types.h>
#include <asm/exception.h>

#define argv_reg(t) (t->task_spot.cpu_context.s[1])
#define envp_reg(t) (t->task_spot.cpu_context.s[2])
#define fp_reg(t) (t->task_spot.cpu_context.s[0])

struct cpu_context {
	unsigned long pc;
	unsigned long sp;	/* Kernel mode stack */
	unsigned long s[12];	/* s[0]: frame pointer */
	struct __riscv_d_ext_state fstate;
};

struct task_spot {
	struct cpu_context cpu_context;
};

static inline void cpu_relax(void)
{
#ifdef __riscv_muldiv
	int dummy;
	/* In lieu of a halt instruction, induce a long-latency stall. */
	__asm__ __volatile__ ("div %0, %0, zero" : "=r" (dummy));
#endif
	barrier();
}

static inline void wait_for_interrupt(void)
{
	__asm__ __volatile__ ("wfi");
}

static inline void __fstate_clean(struct exception_spot *regs)
{
	regs->sstatus = (regs->sstatus & ~SR_FS) | SR_FS_CLEAN;
}

static inline void fstate_off(struct task_desc *task,
			      struct exception_spot *regs)
{
	regs->sstatus = (regs->sstatus & ~SR_FS) | SR_FS_OFF;
}

/**
 * ????
 */
#define ARCH_HAS_PREFETCH
static inline void prefetch(const void *ptr)
{
	__builtin_prefetch(ptr);
}

#define ARCH_HAS_PREFETCHW
static inline void prefetchw(const void *ptr)
{
	__builtin_prefetch(ptr, 1);
}

#define ARCH_HAS_SPINLOCK_PREFETCH
static inline void spin_lock_prefetch(const void *x)
{
	prefetchw(x);
}
extern void (*pm_power_off)(void);
extern void cpu_do_idle(void);
void init_arch_cpu(void);
void arch_restart(char *cmd);
void arch_power_off(void);
void __switch_fpsimd_context(struct task_desc *prev,
	struct task_desc *next);
void __switch_mmu_context(struct process_desc *prev,
	struct process_desc *new);

extern void __switch_cpu_asm(struct task_desc *prev,
	struct task_desc *next, void* tp);
extern void __fstate_save_asm(struct task_desc *tsk);
extern void __fstate_restore_asm(struct task_desc *tsk);
extern void start_user_run(u64 sp);
void start_user_task(struct task_desc *task);
void init_user_context(struct exception_spot* s);
void fork_ret_before(struct exception_spot* s);
void save_fp_regs(struct task_desc *task);
void restore_fp_regs(struct task_desc *task);
void save_tls(struct task_desc *t);
void restore_tls(struct task_desc *t);
void __switch_tls_context(struct task_desc *prev,
	struct task_desc *next);
void dump_task_user_regs(struct exception_spot* s);
int arch_destroy_task(struct task_desc *tsk);

void arch_init_user_regs(struct task_desc * tsk, unsigned long stack);

void arch_init_kernel_regs(struct task_desc * tsk, unsigned long stack, unsigned long argv, unsigned long envp);

void arch_init_fork_kernel_regs(struct task_desc * tsk, unsigned long stack, struct exception_spot* spot);

void arch_init_fork_user_regs(struct task_desc * tsk, unsigned long stack, unsigned long user_stack, struct exception_spot* spot);

void arch_exit_fork_regs(struct task_desc * tsk);

char *arch_get_argv(void);

char *arch_get_envp(void);
void init_master_idle_process(void);
struct device_node;
int riscv_dt_processor_hart(struct device_node *device);
int arch_launch_cpu(unsigned int cpu, void* p);

#endif /* __ASSEMBLY__ */

#endif /* __ASM_PROCESSOR_H */
